package ProtocolXML;


import ProtocolXML.TypeOfMsg;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import lab_2_server.ServerID;
import org.jdom2.* ;

public class Message extends EntityXML {
    public Message() {
        super() ;
    }
    protected Message(Document document) {
        super(document) ;
    }
    /**
     * Set code of message in XML document value
     */
    private TypeOfMsg typeOfMessage = null ;

    private static FilterInter filter = new MyFilter() ;


    //instance msg how "Autorization message"
    protected static final String LOGIN = "Login" ;
    protected static final String PASSWORD = "Password" ;
    public void msgIsAutorization(String login, String password) {
        setTypeMessage(TypeOfMsg.AUTORIZATION);
        getBody().removeContent() ;
        //Add login to XML document
        Element log = new Element(LOGIN) ;
        log.setText(login) ;
        getBody().addContent(log) ;
        //Add password to XML document
        Element passwd = new Element(PASSWORD) ;
        passwd.setText(password) ;
        getBody().addContent(passwd) ;
    }
    //Methods for getting values
    public String getLogin() throws NotCompatibilityTypeException{
        testType(TypeOfMsg.AUTORIZATION);
        return getBody().getChildText(LOGIN) ;
    }
    public String getPassword() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.AUTORIZATION);
        return getBody().getChildText(PASSWORD) ;
    }


    //Instance msg as "User connect to server"
    protected static final String USER_ID = "UserID" ;
    protected static final String USER_NICKNAME = "UserNickName" ;
    public void msgIsUserConnected(int userID, String nickName) {
        setTypeMessage(TypeOfMsg.USER_CONNECT);
        getBody().removeContent() ;

        Element id = new Element(USER_ID) ;
        id.setText(userID+"") ;
        getBody().addContent(id) ;
        //Create and add nickname
        Element nick = new Element(USER_NICKNAME) ;
        nick.setText(nickName) ;
        getBody().addContent(nick) ;
    }
    public int getConnectedUserID() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.USER_CONNECT);
        String id = getBody().getChildText(USER_ID) ;
        return Integer.parseInt(id) ;
    }
    public String getConnectedUserNick() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.USER_CONNECT);
        return getBody().getChildText(USER_NICKNAME) ;
    }


    
    //instance msg how "Disconnect"
    public void msgIsUserDisconnect(int userId) {
        setTypeMessage(TypeOfMsg.DISCONNECT);
        getBody().removeContent() ;
        //Create and add USER_ID to document
        Element userID = new Element(USER_ID) ;
        userID.setText(userId+"") ;
        getBody().addContent(userID) ;
    }
    public int getDisconnectUserId() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.DISCONNECT) ;
        String id = getBody().getChildText(USER_ID) ;
        return Integer.parseInt(id) ;
    }


    
    //instance msg how "Message to user from user"
    protected static final String RECEIVER_USER_ID = "ReceiverID" ;
    protected static final String MESSAGE = "Message" ;
    public void msgIsToSending(int receiverID, String msgToSending) {
        setTypeMessage(TypeOfMsg.SEND_MESSAGE_USR);
        getBody().removeContent() ;
        //Add ReceiverID to document
        
        Element receiverUsrID = new Element(RECEIVER_USER_ID) ;
        receiverUsrID.setText(receiverID+"") ;
        getBody().addContent(receiverUsrID) ;
        //Add message to document
        Element message = new Element(MESSAGE) ;
        message.setText(msgToSending) ;
        getBody().addContent(message) ;
    }


    //instance msg how "Message to user from user (via server)"
    protected static final String SENDER_ID = "SenderID" ;
    public void msgIsSendingToSrv(int receiverID, int senderID, String msgToSending) {
        msgToSending = getFilter().sift( msgToSending ) ;
        msgIsToSending(receiverID, msgToSending) ;
        //Change type of message
        setTypeMessage(TypeOfMsg.SEND_MESSAGE_SRV) ;
        //Create and add sender id to document
        Element sender = new Element(SENDER_ID) ;
        sender.setText(senderID+"") ;
        getBody().addContent(sender) ;
    }


    //Method for get values for  "SEND_MESSAGE_USR" type
    public int getSenderId() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.SEND_MESSAGE_SRV) ;
        String id = getBody().getChildText(SENDER_ID) ;
        return Integer.parseInt(id) ;
    }


    //Method for get values for  "SEND_MESSAGE_USR" and "SEND_MESSAGE_SRV" type
    public int getIdReceiver() throws NotCompatibilityTypeException {
        //Execute test for compatibility queri's method and type of message
        short countExceptins = 0 ;
        try {
            testType(TypeOfMsg.SEND_MESSAGE_USR) ;
        }
        catch(NotCompatibilityTypeException ex) {
            countExceptins++ ;
        }
        try {
            testType(TypeOfMsg.SEND_MESSAGE_SRV) ;
        }
        catch(NotCompatibilityTypeException ex) {
            countExceptins++ ;
        }
        if( countExceptins == 2)
            throw new NotCompatibilityTypeException() ;
        //If the execution reached here, then all is good, return value
        String id = getBody().getChildText(RECEIVER_USER_ID) ;
        return Integer.parseInt(id) ;
    }


    public String getMsg() throws NotCompatibilityTypeException {
        //Execute test for compatibility queri's method and type of message
        short countExceptins = 0 ;
        try {
            testType(TypeOfMsg.SEND_MESSAGE_USR) ;
        }
        catch(NotCompatibilityTypeException ex) {
            countExceptins++ ;
        }
        try {
            testType(TypeOfMsg.SEND_MESSAGE_SRV) ;
        }
        catch(NotCompatibilityTypeException ex) {
            countExceptins++ ;
        }
        if( countExceptins == 2)
            throw new NotCompatibilityTypeException() ;
        //If the execution reached here, then all is good, return value
        return getBody().getChildText(MESSAGE) ;
    }


    
    //Instance ms how "Create group chat"
    protected static final String GROUP_NAME = "GroupName" ;
    public void msgIsCreateGroup(String groupName) {
        setTypeMessage(TypeOfMsg.CREATE_GROUP) ;
        getBody().removeContent() ;

        Element name = new Element(GROUP_NAME) ;
        name.setText(groupName) ;
        getBody().addContent(name) ;
    }
    //method for get value "Group Name"
    public String getGroupName() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.CREATE_GROUP) ;
        return getBody().getChildText(GROUP_NAME) ;
    }


    //*******************************************
    //Instance ms how "Invite user to group chat"
    protected static final String GROUP_ID = "GroupID" ;
    public void msgIsInvUserToGroup(int idUsrToInvite, int idGroupForInvite) {
        setTypeMessage(TypeOfMsg.INV_USER_TO_GROUP);
        getBody().removeContent() ;
        //Create and add "id user to invite" to document
        Element user = new Element(USER_ID) ;
        user.setText(idUsrToInvite+"") ;
        getBody().addContent(user) ;
        //Create and add "id group for invite" to document
        Element group = new Element(GROUP_ID) ;
        group.setText(idGroupForInvite+"") ;
        getBody().addContent(group) ;
    }


    //! FIXME разобраться с Групповым чатом
    //*******************************************
    //Instance ms how "Mesage with ServerID"
    protected static final String SERVER_SAMPLE = "ServerSample" ;
    protected static final String HOST = "Host" ;
    protected static final String PORT = "Port" ;
    protected static final String ALIAS = "Alias" ;
    public void msgIsServerID( ServerID serverID ) {
        setTypeMessage(TypeOfMsg.SERVER_INF);
        getBody().removeContent() ;
        
        //Create and add host
        Element host = new Element(HOST);
        host.setText(serverID.getHost());
        getBody().addContent(host) ;

        //Create and add port
        Element port = new Element(PORT);
        port.setText(serverID.getPort() + "");
        getBody().addContent(port);

        //Create and add alias
        Element alias = new Element(ALIAS);
        alias.setText(serverID.getAlias());
        getBody().addContent(alias);
    }
    //Method for get list of servers
    public ServerID getServerID() throws NotCompatibilityTypeException {
        testType(TypeOfMsg.SERVER_INF);

        
        String host = getBody().getChildText(HOST);
        String alias = getBody().getChildText(ALIAS);
        String portStr = getBody().getChildText(PORT);
        int port = Integer.parseInt(portStr);
        return new ServerID( host, port, alias ) ;
    }
    
    //*******************************************
    // Read object from stream and return his
    public static Message read(InputStream iStream)
            throws JDOMException, IOException, ClassNotFoundException {
        ObjectInputStream inputObject = new ObjectInputStream(iStream) ;
        Document document = (Document) inputObject.readObject() ;
        
        Message msg = new Message(document) ;
        Element type = msg.getHeader().getChild(TYPE) ;
        TypeOfMsg typeOfMsg = convert(type.getText()) ;
        msg.setTypeMessage(typeOfMsg);
        return msg ;
    }

    //Method convert String to TypeOfMsg
    static protected TypeOfMsg convert(String typeInString) {
        if("AUTORIZATION".equals(typeInString))
            return TypeOfMsg.AUTORIZATION ;
        else if("USER_CONNECT".equals(typeInString))
            return TypeOfMsg.USER_CONNECT ;
        else if("DISCONNECT".equals(typeInString))
            return TypeOfMsg.DISCONNECT ;
        else if("SEND_MESSAGE_SRV".equals(typeInString))
            return TypeOfMsg.SEND_MESSAGE_SRV ;
        else if("SEND_MESSAGE_USR".equals(typeInString))
            return TypeOfMsg.SEND_MESSAGE_USR ;
        else if("CREATE_GROUP".equals(typeInString))
            return TypeOfMsg.CREATE_GROUP ;
        else if("INV_USER_TO_GROUP".equals(typeInString))
            return TypeOfMsg.INV_USER_TO_GROUP ;
        else if("SERVER_INF".equals(typeInString))
            return TypeOfMsg.SERVER_INF ;
        else throw new Error("Not can convert from String("+typeInString+") to TypeOfMsg.");
    }


    protected void setTypeMessage(TypeOfMsg messageType) {
        typeOfMessage = messageType ;
        getHeader().getChild(TYPE).setText(messageType.toString()) ;
    }


    public TypeOfMsg getTypeOfMsg() {
        return typeOfMessage ;
    }


    protected void testType(TypeOfMsg type) throws NotCompatibilityTypeException {
        if(!getTypeOfMsg().equals(type))
            throw new NotCompatibilityTypeException() ;
    }

    private static FilterInter getFilter() {
        return filter;
    }

    private static void setFilter(FilterInter filter) {
        Message.filter = filter;
    }


}
